home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 2 / ETO Development Tools 2.iso / Tools - Objects / MacApp / MacApp CD Release / MacApp 2.0.1 (Many Libraries) / Libraries / UMacApp.TWindow.p < prev    next >
Encoding:
Text File  |  1990-10-25  |  45.6 KB  |  1,682 lines  |  [TEXT/MPS ]

  1. {$P}
  2. {[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]}
  3. { UMacApp.TWindow.p }
  4. { Copyright © 1987-1990 by Apple Computer Inc.    All rights reserved. }
  5.  
  6. {--------------------------------------------------------------------------------------------------}
  7. {$S MAClose}
  8.  
  9. PROCEDURE TCloseWindowCommand.DoIt;
  10.  
  11.     BEGIN
  12.     IF fView <> NIL THEN
  13.         TWindow(fView).CloseByUser;
  14.     END;
  15.  
  16. {--------------------------------------------------------------------------------------------------}
  17. {$S MASelCommand}
  18.  
  19. PROCEDURE TCloseWindowCommand.ICloseWindowCommand(itsCmdNumber: CmdNumber;
  20.                                                   itsWindow: TWindow);
  21.  
  22.     BEGIN
  23.     INoChangesCommand(itsCmdNumber, NIL, itsWindow, NIL);
  24.     END;
  25.  
  26. {--------------------------------------------------------------------------------------------------}
  27. {$S MAFields}
  28.  
  29. PROCEDURE TCloseWindowCommand.Fields(PROCEDURE DoToField(fieldName: Str255;
  30.                                                          fieldAddr: Ptr;
  31.                                                          fieldType: integer)); OVERRIDE;
  32.  
  33.     BEGIN
  34.     DoToField('TCloseWindowCommand', NIL, bClass);
  35.  
  36.     INHERITED Fields(DoToField);
  37.     END;
  38.  
  39. {--------------------------------------------------------------------------------------------------}
  40. {$S MAOpen}
  41.  
  42. PROCEDURE TWindow.IWindow(itsDocument: TDocument;
  43.                           itsWMgrWindow: WindowPtr;
  44.                           canResize, canClose, disposeOnFree: BOOLEAN);
  45.  
  46.     VAR
  47.         preDocname:         integer;
  48.         constTitle:         integer;
  49.         aString:            Str255;
  50.         fi:                 FailInfo;
  51.         p:                    Point;
  52.         vp:                 VPoint;
  53.  
  54.     PROCEDURE HandleFailure(error: OSErr;
  55.                             message: LONGINT);
  56.  
  57.         BEGIN
  58.         Free;
  59.         END;
  60.  
  61.     FUNCTION GetSetVPt(v, h: VCoordinate): VPoint;
  62.  
  63.         VAR
  64.             aVPt:                VPoint;
  65.  
  66.         BEGIN
  67.         aVPt.v := v;
  68.         aVPt.h := h;
  69.         GetSetVPt := aVPt;
  70.         END;
  71.  
  72.     BEGIN
  73.     { set up fields necessary to free myself }
  74.     fWMgrWindow := itsWMgrWindow;
  75.     fFreeOnClosing := FALSE;
  76.     fDisposeOnFree := disposeOnFree;
  77.  
  78.     SetPort(GetGrafPort);                                { ??? Why is this necessary? }
  79.     WITH fWMgrWindow^.portRect DO
  80.         BEGIN
  81.         p := topleft;
  82.         LocalToGlobal(p);
  83.         PtToVPt(p, vp);
  84.         IView(itsDocument, NIL, vp, GetSetVPt(bottom - top, right - left), SizeVariable,
  85.               SizeVariable);
  86.         END;
  87.  
  88.     fProcID := GetWindowVariant(itsWMgrWindow);
  89.     SetWRefcon(itsWMgrWindow, LONGINT(SELF));
  90.  
  91.     fAdapted := FALSE;                                    { Set by AdaptToScreen }
  92.     fHorzCentered := FALSE;                             { Set by Center }
  93.     fVertCentered := FALSE;                             { Set by Center }
  94.     fStaggered := FALSE;                                { Set by SimpleStagger }
  95.     fForcedOnScreen := FALSE;                            { Set by ForceOnScreen }
  96.  
  97.     { We can't tell if any changing will be required so we just set these false here.
  98.     If the developer sets them true then we respect them or if the developer calls the
  99.     corresponding functions we set them. }
  100.     fMustAdapt := FALSE;
  101.     fMustHorzCenter := FALSE;
  102.     fMustVertCenter := FALSE;
  103.     fMustStagger := FALSE;
  104.     fMustForceOnScreen := FALSE;
  105.  
  106.     fIsActive := FALSE;
  107.     fIsResizable := canResize;
  108.     fIsClosable := canClose;
  109.     fTarget := SELF;
  110.     fTargetID := fIdentifier;
  111.     fClosesDocument := TRUE;
  112.     fOpenInitially := TRUE;
  113.     fIsModal := FALSE;
  114.     fDoFirstClick := FALSE;
  115.     fFloats := FALSE;
  116.     IF BuildWindowRgns(BuildWindowRgns(kBuild)) THEN;    { sets fContRgnInset & fContDifference }
  117.  
  118.     CatchFailures(fi, HandleFailure);
  119.  
  120.     fMoveBounds := gStdWMoveBounds;
  121.     SetResizeLimits(gStdWSizeRect.topleft, gStdWSizeRect.botRight);
  122.     GetTitle(aString);
  123.     IF ParseTitleTemplate(aString, preDocname, constTitle) THEN
  124.         SetWTitle(itsWMgrWindow, aString);
  125.     fPreDocname := preDocname;
  126.     fConstTitle := constTitle;
  127.  
  128.     InstallDocument(itsDocument);
  129.  
  130.     Success(fi);
  131.     END;
  132.  
  133. {--------------------------------------------------------------------------------------------------}
  134. {$S MAOpen}
  135.  
  136. PROCEDURE TWindow.IRes(itsDocument: TDocument;
  137.                        itsSuperView: TView;
  138.                        VAR itsParams: Ptr);
  139.  
  140.     VAR
  141.         bounds:             Rect;
  142.         aWMgrWindow:        WindowPtr;
  143.         preDocname:         integer;
  144.         constTitle:         integer;
  145.         aString:            Str255;
  146.         fi:                 FailInfo;
  147.  
  148.     PROCEDURE HandleFailure(error: OSErr;
  149.                             message: LONGINT);
  150.  
  151.         BEGIN
  152.         Free;
  153.         END;
  154.  
  155.     BEGIN
  156.     { set up fields necessary to free myself }
  157.     fWMgrWindow := NIL;
  158.     fFreeOnClosing := FALSE;
  159.     fDisposeOnFree := TRUE;
  160.  
  161.     INHERITED IRes(itsDocument, itsSuperView, itsParams);
  162.  
  163.     SetRect(bounds, fLocation.h, fLocation.v, fLocation.h + fSize.h, fLocation.v + fSize.v);
  164.  
  165.     WITH WindowTemplatePtr(itsParams)^ DO
  166.         BEGIN
  167.         CatchFailures(fi, HandleFailure);
  168.  
  169.         { ignore request for zoomDocProc if not 128K ROM, because
  170.         the user might be running pre-3.0 System, which can't
  171.         handle zoomDocProc }
  172.         IF NOT qNeedsROM128K & NOT gConfiguration.hasROM128K THEN
  173.             procID := BAND(procID, $FFF7);
  174.  
  175.         fProcID := procID;
  176.  
  177.         IF qNeedsColorQD | gConfiguration.hasColorQD THEN
  178.             aWMgrWindow := WindowPtr(NewCWindow(NIL, bounds, title, FALSE, procID, Pointer( - 1),
  179.                                                 hasGoAway, ORD4(SELF)))
  180.         ELSE
  181.             aWMgrWindow := NewWindow(NIL, bounds, title, FALSE, procID, Pointer( - 1), hasGoAway,
  182.                                      ORD4(SELF));
  183.         fWMgrWindow := aWMgrWindow;
  184.  
  185.         fAdapted := FALSE;                                { Set by AdaptToScreen }
  186.         fHorzCentered := FALSE;                         { Set by Center }
  187.         fVertCentered := FALSE;                         { Set by Center }
  188.         fStaggered := FALSE;                            { Set by SimpleStagger }
  189.         fForcedOnScreen := FALSE;                        { Set by ForceOnScreen }
  190.         fIsActive := FALSE;
  191.         fIsResizable := resizable;
  192.         fIsClosable := hasGoAway;
  193.         fTarget := SELF;
  194.         fTargetID := targetID;
  195.         fIsModal := isModal;
  196.         fDoFirstClick := doFirstClick;
  197.         fFreeOnClosing := freeOnClosing;
  198.         fDisposeOnFree := disposeOnFree;
  199.         fClosesDocument := closesDocument;
  200.         fOpenInitially := openInitially;
  201.         fMoveBounds := gStdWMoveBounds;
  202.         SetResizeLimits(gStdWSizeRect.topleft, gStdWSizeRect.botRight);
  203.         fFloats := FALSE;
  204.         IF BuildWindowRgns(BuildWindowRgns(kBuild)) THEN; { sets fContRgnInset & fContDifference }
  205.  
  206.         GetTitle(aString);
  207.         IF ParseTitleTemplate(aString, preDocname, constTitle) THEN
  208.             SetWTitle(aWMgrWindow, aString);
  209.         fPreDocname := preDocname;
  210.         fConstTitle := constTitle;
  211.  
  212.         InstallDocument(itsDocument);
  213.  
  214.         Success(fi);
  215.  
  216.         fMustAdapt := mustAdaptToScreen;
  217.         fMustHorzCenter := horzCenter;
  218.         fMustVertCenter := vertCenter;
  219.         fMustStagger := stagger;
  220.         fMustForceOnScreen := mustForceOnScreen;
  221.  
  222.         OffsetPtrWStr(itsParams, SIZEOF(WindowTemplate));
  223.         END;
  224.     END;
  225.  
  226. {--------------------------------------------------------------------------------------------------}
  227. {$S MAWriteRes}
  228.  
  229. PROCEDURE TWindow.WRes(theResource: ViewRsrcHandle;
  230.                        VAR itsParams: Ptr); OVERRIDE;
  231.  
  232.     VAR
  233.         theTitle:            Str255;
  234.         wnPtr:                WindowTemplatePtr;
  235.  
  236.     BEGIN
  237.     INHERITED WRes(theResource, itsParams);
  238.  
  239.     GetTitle(theTitle);
  240.  
  241.     wnPtr := WindowTemplatePtr(ExpandPtrWStr(theResource, itsParams, SIZEOF(WindowTemplate),
  242.                                              LENGTH(theTitle)));
  243.  
  244.     WITH wnPtr^ DO
  245.         BEGIN
  246.         procID := fProcID;
  247.         hasGoAway := fIsClosable;
  248.         resizable := fIsResizable;
  249.         isModal := fIsModal;
  250.         doFirstClick := fDoFirstClick;
  251.         freeOnClosing := fFreeOnClosing;
  252.         disposeOnFree := fDisposeOnFree;
  253.         closesDocument := fClosesDocument;
  254.         openInitially := fOpenInitially;
  255.         mustAdaptToScreen := fMustAdapt;
  256.         stagger := fMustStagger;
  257.         mustForceOnScreen := fMustForceOnScreen;
  258.         vertCenter := fMustVertCenter;
  259.         horzCenter := fMustHorzCenter;
  260.         targetID := fTargetID;
  261.         CopyStr255(theTitle, PRStr(title));
  262.         END;
  263.     END;
  264.  
  265. {--------------------------------------------------------------------------------------------------}
  266. {$S MAWriteRes}
  267.  
  268. PROCEDURE TWindow.WriteRes(theResource: ViewRsrcHandle;
  269.                            VAR itsParams: Ptr); OVERRIDE;
  270.  
  271.     BEGIN
  272.     gWResSignature := 'wind'; gWResType := 'TWindow';
  273.     WRes(theResource, itsParams);
  274.     END;
  275.  
  276. {--------------------------------------------------------------------------------------------------}
  277. {$S MAClose}
  278.  
  279. PROCEDURE TWindow.Free; OVERRIDE;
  280.  
  281.     VAR
  282.         disposeOnFree:        BOOLEAN;
  283.         wmgrWindow:         WindowPtr;
  284.  
  285.     BEGIN
  286.     disposeOnFree := fDisposeOnFree;
  287.     wmgrWindow := fWMgrWindow;
  288.     fWMgrWindow := NIL;                                 { ??? will this help? }
  289.  
  290.     IF fDocument <> NIL THEN
  291.         fDocument.DeleteWindow(SELF)
  292.     ELSE
  293.         gApplication.DeleteFreeWindow(SELF);
  294.  
  295.     INHERITED Free;
  296.  
  297.     { ****** DON'T REFER TO ANY FIELDS OR METHODS OF SELF ****** }
  298.  
  299.     wmgrWindow := FreeIfWMgrWindow(wmgrWindow, disposeOnFree);
  300.     END;
  301.  
  302. {--------------------------------------------------------------------------------------------------}
  303. {$S MAActivate}
  304.  
  305. PROCEDURE TWindow.Activate(entering: BOOLEAN);
  306.  
  307.     VAR
  308.         different:            BOOLEAN;
  309.         aWindow:            TWindow;
  310.  
  311.     BEGIN
  312.     InvalidateFocus;                                    { Must refocus to make sure thePort is set }
  313.     different := entering <> fIsActive;
  314.  
  315.     IF different THEN
  316.         BEGIN
  317.         Update;                                         { Logically the order is wrong, but it gives
  318.                                                          the correct visual effect. ??? Revisit? }
  319.         INHERITED Activate(entering);
  320.  
  321.         IF entering THEN
  322.             BEGIN
  323.             aWindow := gApplication.GetActiveWindow;
  324.             IF aWindow <> NIL THEN                        { So lost deactivate doesn't screw up
  325.                                                          gTarget }
  326.                 aWindow.Activate(FALSE);
  327.             fIsActive := entering;
  328.             gApplication.SetTarget(fTarget);
  329.             END
  330.         ELSE
  331.             BEGIN
  332.             fIsActive := entering;
  333.             gApplication.SetTarget(gApplication);
  334.             SetCursor(arrow);                            { ensure that the cursor is an arrow when
  335.                                                          MacApp loses control }
  336.             END;
  337.         END;
  338.  
  339.     IF fIsResizable & Focus & IsVisible THEN
  340.         DrawResizeIcon;
  341.  
  342.     END;
  343.  
  344. {--------------------------------------------------------------------------------------------------}
  345. {$S MAOpen}
  346.  
  347. PROCEDURE TWindow.AdaptToScreen;
  348.  
  349.     CONST
  350.         stdHScreen            = 512;
  351.         stdVScreen            = 342;
  352.         stdScreen            = $10000 * stdVScreen + stdHScreen;
  353.  
  354.     VAR
  355.         diff:                Point;
  356.         windRect:            Rect;
  357.         newSize:            Point;
  358.         theLimits:            Rect;
  359.  
  360.     BEGIN
  361.     fAdapted := TRUE;                                    { We adapted to the screen }
  362.     { Compute difference between current screen and std Mac screen }
  363.     diff := screenBits.bounds.botRight;
  364.     SubPt(screenBits.bounds.topleft, diff);
  365.     SubPt(Point(stdScreen), diff);
  366.     GetGlobalBounds(windRect);
  367.  
  368.     { If screen is larger, enlarge the window. If the window is too large, shrink it }
  369.     IF (LONGINT(diff) <> 0) | (windRect.bottom > screenBits.bounds.bottom) | { do an adjustment for
  370.            larger screen }
  371.        (windRect.right > screenBits.bounds.right) THEN
  372.         BEGIN
  373.         newSize := windRect.botRight;
  374.         AddPt(diff, newSize);                            { the window adapted to the new screen size
  375.                                                          }
  376.         theLimits := fResizeLimits;
  377.         WITH theLimits DO
  378.             BEGIN
  379.             { Consider the location of the window, bound it by the resize limits }
  380.             newSize.v := MinMax(top, newSize.v - windRect.top, bottom);
  381.             newSize.h := MinMax(left, newSize.h - windRect.left, right);
  382.             END;
  383.  
  384.         Resize(newSize.h, newSize.v, kInvalidate);
  385.  
  386.         END;
  387.     END;
  388.  
  389. {--------------------------------------------------------------------------------------------------}
  390. {$S MAWindowRes}
  391.  
  392. FUNCTION TWindow.AllowsMenuAccess: BOOLEAN;
  393.  
  394.     BEGIN
  395.     { Default is to always allow menu access, even if modal }
  396.     AllowsMenuAccess := TRUE;
  397.     END;
  398.  
  399. {--------------------------------------------------------------------------------------------------}
  400. {$S MANonRes}
  401.  
  402. FUNCTION GetAndLoadWDefProc(windowDefProc: Handle): Handle;
  403. { utility routine: given a windowDefProc, this routine returns its actual address and loads it }
  404.  
  405.     VAR
  406.         wDefProc:            Handle;
  407.  
  408.     BEGIN
  409.     wDefProc := Handle(StripLong(windowDefProc));
  410.     IF wDefProc^ = NIL THEN
  411.         LoadResource(wDefProc);
  412.     GetAndLoadWDefProc := wDefProc;
  413.     END;
  414.  
  415. {--------------------------------------------------------------------------------------------------}
  416.  
  417. FUNCTION CallWDefProc(varCode: integer;
  418.                       theWindow: WindowPtr;
  419.                       message: integer;
  420.                       param: LONGINT;
  421.                       wDefProc: UNIV Handle): LONGINT;
  422.     INLINE $205F,                                        { MOVE.L (A7)+,A0 }
  423.            $2050,                                        { MOVE.L (A0),A0 }
  424.            $4E90;                                        { JSR (A0) }
  425.  
  426. {--------------------------------------------------------------------------------------------------}
  427. {$S MAOpen}
  428.  
  429. PROCEDURE TWindow.Center(horizontally, vertically, forDialog: BOOLEAN);
  430.  
  431.     VAR
  432.         windowSize:         Point;
  433.         screenSize:         Point;
  434.         contentSize:        Point;
  435.         bottomRightInset:    Point;
  436.         globalbounds, screenRect: Rect;
  437.         rgnsWereBuilt:        BOOLEAN;
  438.  
  439.     BEGIN
  440.     fHorzCentered := horizontally;
  441.     fVertCentered := vertically;
  442.     IF (fWMgrWindow <> NIL) & (horizontally | vertically) THEN
  443.         BEGIN
  444.         IF GetMaxIntersectedDevice(screenRect) = NIL THEN; { don't care about result }
  445.         WITH screenRect DO
  446.             BEGIN
  447.             screenSize.h := right - left;
  448.             screenSize.v := bottom - top;                { NOTE: GetMaxIntersectedDevice accounts for
  449.                                                          menubar so don't subtract gMbarHeight }
  450.             END;
  451.  
  452.         WITH WindowPeek(fWMgrWindow)^ DO
  453.             BEGIN
  454.             rgnsWereBuilt := BuildWindowRgns(kBuild);
  455.             WITH strucRgn^^.rgnBBox DO
  456.                 BEGIN
  457.                 windowSize.h := right - left;
  458.                 windowSize.v := bottom - top;
  459.                 END;
  460.             IF BuildWindowRgns(rgnsWereBuilt) THEN;     { discard result }
  461.  
  462.             GetGlobalBounds(globalbounds);
  463.             WITH globalbounds DO
  464.                 BEGIN
  465.                 contentSize.h := right - left;
  466.                 contentSize.v := bottom - top;
  467.                 END;
  468.  
  469.             { The top-left content inset isn't enough; factor in the amount to the right of the }
  470.             { content also. }
  471.             bottomRightInset := windowSize;
  472.             SubPt(contentSize, bottomRightInset);
  473.             SubPt(fContRgnInset, bottomRightInset);
  474.             {$PUSH} {$H-}
  475.             SubPt(bottomRightInset, fContRgnInset);
  476.             {$POP}
  477.             END;
  478.  
  479.         WITH globalbounds DO
  480.             BEGIN
  481.             IF horizontally THEN
  482.                 left := (screenSize.h - contentSize.h + fContRgnInset.h) DIV 2;
  483.             IF vertically THEN
  484.                 IF forDialog THEN
  485.                 { Put it in the top third of the screen }
  486.                     top := ((screenSize.v - contentSize.v + fContRgnInset.v) DIV 3) + 20
  487.                 ELSE
  488.                     top := ((screenSize.v - contentSize.v + fContRgnInset.v) DIV 2) + 20;
  489.             END;
  490.         Locate(globalbounds.left, globalbounds.top, kDontInvalidate);
  491.         END;
  492.     END;
  493.  
  494. {--------------------------------------------------------------------------------------------------}
  495. {$S MAClose}
  496.  
  497. PROCEDURE TWindow.Close; OVERRIDE;
  498.  
  499.     BEGIN
  500.     INHERITED Close;
  501.  
  502.     Show(FALSE, kRedraw);
  503.     Activate(FALSE);                                    { ??? Is this necessary? }
  504.  
  505.     IF fFreeOnClosing THEN
  506.         Free;
  507.     END;
  508.  
  509. {--------------------------------------------------------------------------------------------------}
  510. {$S MAClose}
  511.  
  512. PROCEDURE TWindow.CloseByUser;
  513.  
  514.     BEGIN
  515.     IF fDocument = NIL THEN                             { free window }
  516.         Close
  517.     ELSE
  518.         fDocument.CloseView(SELF);
  519.     END;
  520.  
  521. {--------------------------------------------------------------------------------------------------}
  522. {$S MASelCommand}
  523.  
  524. FUNCTION TWindow.DoMenuCommand(aCmdNumber: CmdNumber): TCommand; OVERRIDE;
  525.  
  526.     VAR
  527.         aCloseWindowCommand: TCloseWindowCommand;
  528.         oldObjectPerm:        BOOLEAN;
  529.  
  530.     BEGIN
  531.     DoMenuCommand := NIL;
  532.  
  533.     CASE aCmdNumber OF
  534.         cClose:
  535.             BEGIN
  536.             oldObjectPerm := AllocateObjectsFromPerm(FALSE); { Guarantee the allocation }
  537.             New(aCloseWindowCommand);
  538.             IF AllocateObjectsFromPerm(oldObjectPerm) THEN;
  539.  
  540.             FailNil(aCloseWindowCommand);                { just in case }
  541.             aCloseWindowCommand.ICloseWindowCommand(aCmdNumber, SELF);
  542.             DoMenuCommand := aCloseWindowCommand;
  543.             END;
  544.         OTHERWISE
  545.             DoMenuCommand := INHERITED DoMenuCommand(aCmdNumber);
  546.     END;
  547.  
  548.     END;
  549.  
  550. {--------------------------------------------------------------------------------------------------}
  551. {$S MAWindowRes}
  552.  
  553. PROCEDURE TWindow.DoSetupMenus; OVERRIDE;
  554.  
  555.     BEGIN
  556.     IF NOT fIsModal THEN                                { Don't enable menu/app commands if modal }
  557.         BEGIN
  558.         Enable(cClose, fIsClosable);                    { window objects take care of themselves! }
  559.  
  560.         INHERITED DoSetupMenus;
  561.         END;
  562.     END;
  563.  
  564. {--------------------------------------------------------------------------------------------------}
  565. {$S MAWindowRes}
  566.  
  567. PROCEDURE TWindow.DrawContents; OVERRIDE;
  568.  
  569.     VAR
  570.         visRect:            Rect;
  571.         {$IFC qExperimentalAndUnsupported}
  572.         fi:                    FailInfo;
  573.         oldgEnableDoubleBuffering: Boolean;
  574.         {$EndC}
  575.  
  576.     PROCEDURE HdlDrawContents(error: OSErr;
  577.                               message: LONGINT);
  578.     
  579.         BEGIN
  580.         {$IFC qExperimentalAndUnsupported}
  581.         gEnableDoubleBuffering := oldgEnableDoubleBuffering;
  582.         {$EndC}
  583.         END;
  584.     
  585.     PROCEDURE DoDrawContents;
  586.     
  587.         VAR
  588.             visRect:            Rect;
  589.     
  590.         BEGIN
  591.         IF Focus THEN
  592.             BEGIN
  593.             { Ensure that the background is correct }
  594.             GetVisibleRect(visRect);
  595.             EraseRect(visRect);
  596.     
  597.             INHERITED DrawContents;
  598.     
  599.             { Draw the resize icon last so other views don't munch it.
  600.             ??? Should the resize icon be a subview that is always drawn last?}
  601.             IF fIsResizable THEN
  602.                 DrawResizeIcon;
  603.             END;
  604.         END;
  605.  
  606.     BEGIN
  607.     {$IFC qExperimentalAndUnsupported}
  608.     IF Focus & IsVisible THEN
  609.         BEGIN
  610.         IF gEnableDoubleBuffering & NOT (gPrinting | gDrawingPictScrap) THEN
  611.             BEGIN
  612.             oldgEnableDoubleBuffering := gEnableDoubleBuffering;
  613.             gEnableDoubleBuffering := FALSE;            { so subviews won't attempt to do off screen
  614.                                                          }
  615.             CatchFailures(fi, HdlDrawContents);
  616.             DoOffScreen(DoDrawContents);
  617.             Success(fi);
  618.             gEnableDoubleBuffering := oldgEnableDoubleBuffering;
  619.             END
  620.         ELSE
  621.             DoDrawContents;
  622.         END;
  623.     {$ELSEC}
  624.     DoDrawContents;
  625.     {$EndC}
  626.     END;
  627.  
  628. {--------------------------------------------------------------------------------------------------}
  629. {$S MAWindowRes}
  630.  
  631. PROCEDURE TWindow.DrawResizeIcon;
  632.  
  633.     VAR
  634.         r:                    Rect;
  635.  
  636.     BEGIN
  637.     IF qDebug THEN
  638.         AssumeFocused;
  639.  
  640.     GetQDExtent(r);
  641.     r.left := r.right - kSBarSizeMinus1;
  642.     r.top := r.bottom - kSBarSizeMinus1;
  643.  
  644.     {$IFC qDebug}
  645.     UseTempRgn('TWindow.DrawResizeIcon');
  646.     {$ENDC}
  647.  
  648.     GetClip(gTempRgn);
  649.     ClipRect(r);
  650.     PenNormal;
  651.     DrawGrowIcon(fWMgrWindow);
  652.     SetClip(gTempRgn);
  653.  
  654.     {$IFC qDebug}
  655.     DoneWithTempRgn;
  656.     {$ENDC}
  657.     END;
  658.  
  659. {--------------------------------------------------------------------------------------------------}
  660. {$S MAWindowRes}
  661.  
  662. FUNCTION TWindow.Focus: BOOLEAN; OVERRIDE;
  663.  
  664. {$IFC qDebug OR qExperimentalAndUnsupported}
  665.  
  666.     VAR
  667.         {$EndC}
  668.         {$IFC qDebug}
  669.         currentPort:        GrafPtr;
  670.         {$ENDC}
  671.         {$IFC qExperimentalAndUnsupported}
  672.         aFocusRec:            FocusRec;
  673.         {$EndC}
  674.  
  675.     BEGIN
  676.     Focus := TRUE;                                        { Hope for the best }
  677.  
  678.     IF IsFocused THEN
  679.         BEGIN
  680.         {$IFC qDebug}
  681.         IF LONGINT(GetGrafPort^.portRect.topleft) <> 0 THEN
  682.             ProgramBreak('TWindow.Focus: Origin is not (0,0)');
  683.  
  684.         GetPort(currentPort);
  685.         IF currentPort <> GetGrafPort THEN
  686.             BEGIN
  687.             ProgramBreak('TWindow.Focus: Port is incorrect');
  688.             Focus := FALSE
  689.             END;
  690.         {$ENDC}
  691.         Exit(Focus);
  692.         END;
  693.  
  694.     {$IFC qExperimentalAndUnsupported}
  695.     IF fFocusRec.IsValid THEN
  696.         BEGIN
  697.         aFocusRec := fFocusRec;
  698.         SetFocus(aFocusRec);
  699.         Exit(Focus);
  700.         END;
  701.     {$EndC}
  702.  
  703.     IF (gDrawingPictScrapView = SELF) | ((gCurrPrintHandler <> NIL) & (gCurrPrintHandler.fView =
  704.        SELF)) THEN
  705.         BEGIN
  706.         { GrafPort has been supplied }
  707.         gFocusedView := SELF;
  708.         END
  709.  
  710.     ELSE IF fWMgrWindow <> NIL THEN
  711.         BEGIN
  712.         SetPort(GetGrafPort);
  713.         SetOrigin(0, 0);
  714.         gLongOffset := gZeroVPt;
  715.         SetClip(thePort^.visRgn);
  716.         gFocusedView := SELF;
  717.  
  718.         {$IFC qExperimentalAndUnsupported}
  719.         aFocusRec.clip := fFocusRec.clip;
  720.         GetFocus(aFocusRec);
  721.         fFocusRec := aFocusRec;
  722.         {$EndC}
  723.         END
  724.     ELSE
  725.         BEGIN
  726.         { If we get this far, then we can't focus }
  727.         ClipRect(gZeroRect);
  728.         InvalidateFocus;
  729.         Focus := FALSE;
  730.         END;
  731.     END;
  732.  
  733. {--------------------------------------------------------------------------------------------------}
  734. {$S MAWindowRes}
  735.  
  736. FUNCTION TWindow.FocusOnSuperView: BOOLEAN; OVERRIDE;
  737.  
  738.     BEGIN
  739.     FocusOnSuperView := FALSE;
  740.     END;
  741.  
  742. {--------------------------------------------------------------------------------------------------}
  743. {$S MAOpen}
  744.  
  745. PROCEDURE TWindow.ForceOnScreen;
  746.  
  747. { ForceOnScreen guarantees that some minimal drag area is accessible to the user, to be dragged
  748.   to the desired location. }
  749.  
  750.     CONST
  751.         kMinDragArea        = 4;                        { ??? should this be settable? }
  752.  
  753.     VAR
  754.         global:             Rect;
  755.         deltaH:             integer;
  756.         deltaV:             integer;
  757.         aTempRgn:            RgnHandle;
  758.         rgnsWereBuilt:        BOOLEAN;
  759.  
  760.     PROCEDURE AdjustGlobalBounds(VAR boundsToAdjust: Rect);
  761.     { assume "boundsToAdjust" is set to the window bounds in global coordinates }
  762.  
  763.         VAR
  764.             visScreenRect:        Rect;
  765.  
  766.         BEGIN
  767.         { since we don't _really_ know what the drag rgn is, we'll assume that moving the topleft
  768.           pt of the window on screen is sufficient to make it draggable, so calculate the deltas
  769.           necessary to move the topleft pt into visible screen rect }
  770.  
  771.         IF GetMaxIntersectedDevice(visScreenRect) = NIL THEN; { NOTE: uses gTempRgn }
  772.         InsetRect(visScreenRect, kMinDragArea, kMinDragArea);
  773.         WITH visScreenRect DO
  774.             BEGIN
  775.             IF boundsToAdjust.top < top THEN
  776.                 deltaV := top - boundsToAdjust.top + fContRgnInset.v
  777.             ELSE IF boundsToAdjust.top > bottom THEN
  778.                 deltaV := bottom - boundsToAdjust.top - fContRgnInset.v;
  779.  
  780.             IF boundsToAdjust.left < left THEN
  781.                 deltaH := left - boundsToAdjust.left + fContRgnInset.h
  782.             ELSE IF boundsToAdjust.left > right THEN
  783.                 deltaH := right - boundsToAdjust.right - fContRgnInset.h;
  784.             END;
  785.         END;
  786.  
  787.     BEGIN
  788.     fForcedOnScreen := TRUE;
  789.  
  790.     deltaH := 0;
  791.     deltaV := 0;
  792.  
  793.         { On many systems (including Color QD & the Radius FPD), it's possible to have a
  794.         non-rectangular desktop.    Try to be nice to people who saved windows
  795.         on secondary screens.  GrayRgn is the true indicator of the shape
  796.         of the desktop--screenBits.bounds is the size of the screen with the
  797.         menu bar on it. }
  798.  
  799.     {$IFC qDebug}
  800.     UseTempRgn('ForceOnScreen');
  801.     {$ENDC}
  802.  
  803.     rgnsWereBuilt := BuildWindowRgns(kBuild);
  804.     WITH WindowPeek(fWMgrWindow)^ DO
  805.         BEGIN
  806.         DiffRgn(strucRgn, contRgn, gTempRgn);            { strucRgn less contRgn ≈≈ drag rgn }
  807.         IF EmptyRgn(gTempRgn) THEN
  808.             CopyRgn(strucRgn, gTempRgn);                { at least get the strucRgn }
  809.         END;                                            { WITH WindowPeek(fWMgrWindow)^ }
  810.     IF BuildWindowRgns(rgnsWereBuilt) THEN;             { discard result }
  811.  
  812.     { get the desktop rgn, inset by a minimal drag area }
  813.     aTempRgn := MakeNewRgn;
  814.     CopyRgn(GetGrayRgn, aTempRgn);                        { aTempRgn := desktop rgn }
  815.     InsetRgn(aTempRgn, kMinDragArea, kMinDragArea);     { inset aTempRgn }
  816.     SectRgn(gTempRgn, aTempRgn, aTempRgn);                { do drag rgn & desktop rgn instersect ? }
  817.     {$IFC qDebug}
  818.     DoneWithTempRgn;                                    { (AdjustGlobalBounds needs gTempRgn) }
  819.     {$ENDC}
  820.  
  821.     GetGlobalBounds(global);
  822.  
  823.     IF EmptyRgn(aTempRgn) | NOT IsDraggable(aTempRgn^^.rgnBBox) THEN
  824.         AdjustGlobalBounds(global);                     { no => adjust the window's global bounds }
  825.     DisposeRgn(aTempRgn);
  826.     OffsetRect(global, deltaH, deltaV);
  827.     WITH global DO
  828.         Locate(left, top, kDontInvalidate);
  829.     END;
  830.  
  831. {--------------------------------------------------------------------------------------------------}
  832. {$S MAWindowRes}
  833.  
  834. PROCEDURE TWindow.GetGlobalBounds(VAR globalbounds: Rect);
  835.  
  836.     VAR
  837.         savedPort:            GrafPtr;
  838.  
  839.     BEGIN
  840.     IF fWMgrWindow = NIL THEN
  841.         globalbounds := gZeroRect                        { CSK 89.11.30 }
  842.     ELSE
  843.         BEGIN
  844.         GetPort(savedPort);
  845.         SetPort(GetGrafPort);
  846.         globalbounds := GetGrafPort^.portRect;
  847.         LocalToGlobal(globalbounds.topleft);
  848.         LocalToGlobal(globalbounds.botRight);
  849.         SetPort(savedPort);
  850.         END;
  851.     END;
  852.  
  853. {--------------------------------------------------------------------------------------------------}
  854. {$S MANonRes}
  855.  
  856. FUNCTION TWindow.GetMaxIntersectedDevice(VAR screenRect: Rect): GDHandle;
  857.  
  858.     PROCEDURE CalcScreenRect;
  859.  
  860.         VAR
  861.             aGDHandle, maxSectGD: GDHandle;
  862.             globalStrucRect, aGDScreenRect: Rect;
  863.             gdSectRect, dontCare: Rect;
  864.             sectArea:            LONGINT;
  865.             maxSectArea:        LONGINT;
  866.             moveBounds:         Rect;
  867.             rgnsWereBuilt:        BOOLEAN;
  868.  
  869.         BEGIN
  870.         rgnsWereBuilt := BuildWindowRgns(kBuild);        { sets fContRgnInset & fContDifference, and
  871.                                                          make sure contrgn and strucrgn are
  872.                                                          available }
  873.         globalStrucRect := WindowPeek(fWMgrWindow)^.strucRgn^^.rgnBBox;
  874.         IF BuildWindowRgns(rgnsWereBuilt) THEN;         { discard result }
  875.  
  876.         moveBounds := fMoveBounds;
  877.  
  878.         aGDHandle := GetDeviceList;
  879.         maxSectGD := GetMainDevice;                     { set as best choice default }
  880.         maxSectArea := 0;
  881.         REPEAT                                            { calc which scrn intersects largest part of
  882.                                                          window }
  883.             BEGIN
  884.             aGDScreenRect := aGDHandle^^.gdRect;
  885.             IF SectRect(aGDScreenRect, moveBounds, dontCare) & SectRect(globalStrucRect,
  886.                                                                         aGDScreenRect,
  887.                gdSectRect) THEN
  888.                 BEGIN
  889.                 WITH gdSectRect DO
  890.                     sectArea := IntMultiply(bottom - top, right - left);
  891.                 IF sectArea > maxSectArea THEN            { do we have a new winner? }
  892.                     BEGIN
  893.                     maxSectArea := sectArea;
  894.                     maxSectGD := aGDHandle;
  895.                     END;
  896.                 END;
  897.             aGDHandle := GetNextDevice(aGDHandle);
  898.             END;
  899.         UNTIL aGDHandle = NIL;
  900.  
  901.         IF maxSectGD <> GetMainDevice THEN
  902.             screenRect := maxSectGD^^.gdRect
  903.         ELSE
  904.             BEGIN                                        { Account for menu bar on the main screen.
  905.                                                          Don't just assume that its at the top of
  906.                                                          the screen! }
  907.             {$IFC qDebug}
  908.             UseTempRgn('TWindow.GetMaxIntersectedDevice');
  909.             {$ENDC}
  910.             RectRgn(gTempRgn, maxSectGD^^.gdRect);        { main screen with menubar }
  911.             SectRgn(gTempRgn, GetGrayRgn, gTempRgn);    { GetGrayRgn = desktop rgn w/o menubar }
  912.             screenRect := gTempRgn^^.rgnBBox;            { => main screen w/o menubar }
  913.             {$IFC qDebug}
  914.             DoneWithTempRgn;
  915.             {$ENDC}
  916.             END;
  917.         GetMaxIntersectedDevice := maxSectGD;
  918.         END;
  919.  
  920.     BEGIN
  921.     IF qNeedsColorQD | gConfiguration.hasColorQD THEN
  922.         CalcScreenRect
  923.     ELSE
  924.         BEGIN                                            { Account for menu bar on the main screen.
  925.                                                          Don't just assume that its at the top of
  926.                                                          the screen! }
  927.         GetMaxIntersectedDevice := NIL;                 { we only have GDHandle in CQD world }
  928.         {$IFC qDebug}
  929.         UseTempRgn('TWindow.GetMaxIntersectedDevice');
  930.         {$ENDC}
  931.         RectRgn(gTempRgn, screenBits.bounds);            { main screen with menubar }
  932.         SectRgn(gTempRgn, GetGrayRgn, gTempRgn);        { GetGrayRgn = desktop rgn w/o menubar }
  933.         screenRect := gTempRgn^^.rgnBBox;                { => main screen w/o menubar }
  934.         {$IFC qDebug}
  935.         DoneWithTempRgn;
  936.         {$ENDC}
  937.         END;
  938.     END;
  939.  
  940. {--------------------------------------------------------------------------------------------------}
  941. {$S MAInspector}
  942.  
  943. PROCEDURE TWindow.GetInspectorName(VAR inspectorName: Str255); OVERRIDE;
  944.  
  945.     BEGIN
  946.     IF (fWMgrWindow <> NIL) & (NOT ODD(ORD4(fWMgrWindow))) THEN
  947.         GetTitle(inspectorName);
  948.     END;
  949.  
  950. {--------------------------------------------------------------------------------------------------}
  951. {$S MAWindowRes}
  952.  
  953. FUNCTION TWindow.GetGrafPort: GrafPtr; OVERRIDE;
  954.  
  955.     BEGIN
  956.     IF gPrinting | gDrawingPictScrap THEN
  957.         GetGrafPort := thePort                            {thePort assumed to be set by print handler}
  958.     ELSE IF fWMgrWindow <> NIL THEN
  959.         GetGrafPort := GrafPtr(fWMgrWindow)
  960.     ELSE
  961.         GetGrafPort := NIL;
  962.     END;
  963.  
  964. {--------------------------------------------------------------------------------------------------}
  965. {$S MAWindowRes}
  966.  
  967. PROCEDURE TWindow.GetTitle(VAR theTitle: Str255);
  968.  
  969.     BEGIN
  970.     GetWTitle(fWMgrWindow, theTitle);
  971.     END;
  972.  
  973. {--------------------------------------------------------------------------------------------------}
  974. {$S MAWindowRes}
  975.  
  976. FUNCTION TWindow.GetWindow: TWindow; OVERRIDE;
  977.  
  978.     BEGIN
  979.     GetWindow := SELF;
  980.     END;
  981.  
  982. {--------------------------------------------------------------------------------------------------}
  983. {$S MAClose}
  984.  
  985. PROCEDURE TWindow.GoAwayByUser(globalMouse: Point);
  986.  
  987.     VAR
  988.         aCloseWindowCommand: TCloseWindowCommand;
  989.         oldObjectPerm:        BOOLEAN;
  990.  
  991.     BEGIN
  992.     IF fIsClosable & TrackGoAway(fWMgrWindow, globalMouse) THEN
  993.         BEGIN
  994.         oldObjectPerm := AllocateObjectsFromPerm(FALSE); { Guarantee the allocation }
  995.         New(aCloseWindowCommand);
  996.         IF AllocateObjectsFromPerm(oldObjectPerm) THEN;
  997.  
  998.         FailNil(aCloseWindowCommand);                    { just in case }
  999.         aCloseWindowCommand.ICloseWindowCommand(cClose, SELF);
  1000.         PostCommand(aCloseWindowCommand);
  1001.         END;
  1002.     END;
  1003.  
  1004. {--------------------------------------------------------------------------------------------------}
  1005. {$S MASelCommand}
  1006.  
  1007. FUNCTION TWindow.HandleMouseDown(theMouse: VPoint;
  1008.                                  VAR info: EventInfo;
  1009.                                  VAR hysteresis: Point;
  1010.                                  VAR theCommand: TCommand): BOOLEAN; OVERRIDE;
  1011.  
  1012.     CONST
  1013.         systemEventMask     = app4Mask;                 { !!! defined as OSEvt in the MPW 3.1
  1014.                                                          interfaces }
  1015.  
  1016.     VAR
  1017.         wantsTheMouse:        BOOLEAN;
  1018.         anEvent:            EventRecord;
  1019.         aWMgrWindow:        WindowPtr;
  1020.         whereMouseDown:     integer;
  1021.  
  1022.     BEGIN
  1023.     theCommand := NIL;
  1024.     HandleMouseDown := TRUE;
  1025.  
  1026.     WITH info, thePEvent^ DO
  1027.         BEGIN
  1028.         whereMouseDown := FindWindow(where, aWMgrWindow);
  1029.  
  1030.         IF aWMgrWindow = fWMgrWindow THEN
  1031.             BEGIN
  1032.             CASE whereMouseDown OF
  1033.                 inContent:
  1034.                     BEGIN
  1035.                     wantsTheMouse := TRUE;
  1036.                     IF gApplication.GetActiveWindow <> SELF THEN
  1037.                         BEGIN
  1038.                         Select;
  1039.                         IF fDoFirstClick THEN
  1040.                         { Make sure this window is activated and updated }
  1041.                             gApplication.UpdateAllWindows
  1042.                         ELSE
  1043.                             wantsTheMouse := FALSE;
  1044.                         END;
  1045.  
  1046.                     IF wantsTheMouse THEN
  1047.                         HandleMouseDown := INHERITED HandleMouseDown(theMouse, info, hysteresis,
  1048.                                                                      theCommand)
  1049.                     ELSE
  1050.                         HandleMouseDown := FALSE;
  1051.                     END;
  1052.  
  1053.                 inDrag:
  1054.                     MoveByUser(where);
  1055.  
  1056.                 inGrow:
  1057.                     ResizeByUser(where);
  1058.  
  1059.                 inGoAway:
  1060.                     GoAwayByUser(where);
  1061.  
  1062.                 inZoomIn, inZoomOut:
  1063.                     ZoomByUser(where, whereMouseDown);
  1064.  
  1065.                 inDesk: ;
  1066.  
  1067.             END;
  1068.             END
  1069.         ELSE IF qDebug THEN
  1070.             ProgramBreak(
  1071.                      'in TWindow.HandleMouseDown: passed an event that didn''t belong to the window'
  1072.                          );
  1073.         END;
  1074.     END;
  1075.  
  1076. {--------------------------------------------------------------------------------------------------}
  1077. {$S MAWindowRes}
  1078.  
  1079. FUNCTION TWindow.HasPendingUpdate: BOOLEAN;
  1080.  
  1081.     BEGIN
  1082.     HasPendingUpdate := NOT EmptyRgn(WindowPeek(fWMgrWindow)^.updateRgn);
  1083.     END;
  1084.  
  1085. {--------------------------------------------------------------------------------------------------}
  1086. {$S MAOpen}
  1087.  
  1088. PROCEDURE TWindow.InstallDocument(itsDocument: TDocument);
  1089.  
  1090.     VAR
  1091.         aString:            Str255;
  1092.  
  1093.     BEGIN
  1094.     fDocument := itsDocument;
  1095.     IF itsDocument <> NIL THEN
  1096.         BEGIN
  1097.         gApplication.DeleteFreeWindow(SELF);            { Just in case… }
  1098.         itsDocument.AddWindow(SELF);
  1099.         aString := itsDocument.fTitle^^;                { SetTitleForDoc may move memory }
  1100.         IF aString <> '' THEN                            { not an untitled document }
  1101.             SetTitleForDoc(aString);
  1102.         fNextHandler := itsDocument;
  1103.         END
  1104.     ELSE
  1105.         BEGIN
  1106.         gApplication.AddFreeWindow(SELF);
  1107.         fNextHandler := gApplication;
  1108.         END;
  1109.     END;
  1110.  
  1111. {--------------------------------------------------------------------------------------------------}
  1112.  
  1113. FUNCTION PushLong(h, v: integer): LONGINT;
  1114. { This can be used to push a longint given a point.     PushLong(aPt.h,aPt.v); }
  1115.     INLINE $2E9F;                                        { MOVE.L (A7)+,(A7) }
  1116.  
  1117. {--------------------------------------------------------------------------------------------------}
  1118. {$S MANonRes}
  1119.  
  1120. FUNCTION TWindow.IsDraggable(whichRect: Rect): BOOLEAN;
  1121. { Returns TRUE if any of the corner points of whichRect are draggable. }
  1122.  
  1123.     VAR
  1124.         wDefProc:            Handle;
  1125.         variant:            integer;
  1126.         dontCare:            LONGINT;
  1127.         saveState:            SignedByte;
  1128.         rgnsWereBuilt:        BOOLEAN;
  1129.  
  1130.     BEGIN
  1131.     IsDraggable := TRUE;
  1132.     rgnsWereBuilt := BuildWindowRgns(kBuild);            { regions needed for hit testing }
  1133.     wDefProc := GetAndLoadWDefProc(WindowPeek(fWMgrWindow)^.windowDefProc);
  1134.     variant := GetWindowVariant(fWMgrWindow);
  1135.     saveState := GetHandleBits(wDefProc);
  1136.     LockHandleHigh(wDefProc);
  1137.  
  1138.     WITH whichRect DO                                    { is any corner pt in the drag region? }
  1139.         IF (CallWDefProc(variant, fWMgrWindow, wHit, PushLong(left, top), wDefProc) <> wInDrag) &
  1140.            (CallWDefProc(variant, fWMgrWindow, wHit, PushLong(right, bottom), wDefProc) <>
  1141.            wInDrag) & (CallWDefProc(variant, fWMgrWindow, wHit, PushLong(left, bottom),
  1142.            wDefProc) <> wInDrag) & (CallWDefProc(variant, fWMgrWindow, wHit, PushLong(right, top),
  1143.                                                   wDefProc) <> wInDrag) THEN
  1144.             IsDraggable := FALSE;                        { …no, so window _isn't_ draggable }
  1145.  
  1146.     SetHandleBits(wDefProc, saveState);
  1147.     IF BuildWindowRgns(rgnsWereBuilt) THEN;             { discard result }
  1148.     END;
  1149.  
  1150. {--------------------------------------------------------------------------------------------------}
  1151. {$S MANonRes}
  1152.  
  1153. FUNCTION TWindow.BuildWindowRgns(build: BOOLEAN): BOOLEAN;
  1154. { Calculate window size including structure region (i.e. title bar).  To do this
  1155.  we need to force the window to compute its structure region by calling its defproc,
  1156.  if the window isn't shown.
  1157.  IF build is FALSE, set the regions back to empty regions, so as not to confuse the
  1158.  window manager.
  1159.  Return the previous state of the regions. }
  1160.  
  1161.     VAR
  1162.         dontCare:            LONGINT;
  1163.         wDefProc:            Handle;
  1164.         topLeftInset, contDifference: Point;
  1165.         globalStrucRect, globalContRect: Rect;
  1166.         saveState:            SignedByte;
  1167.  
  1168.     BEGIN
  1169.     WITH WindowPeek(fWMgrWindow)^ DO
  1170.         BEGIN
  1171.         { The regions are considered to be built if either:
  1172.           a) the window is shown; or
  1173.           b) the structure rgn is not empty. }
  1174.         IF IsShown | NOT EmptyRgn(strucRgn) THEN
  1175.             BEGIN
  1176.             BuildWindowRgns := kBuild;
  1177.             IF (build <> kBuild) & NOT IsShown THEN
  1178.                 BEGIN
  1179.                 SetEmptyRgn(strucRgn);
  1180.                 SetEmptyRgn(contRgn);
  1181.                 END;
  1182.             END
  1183.         ELSE
  1184.             BEGIN
  1185.             BuildWindowRgns := NOT kBuild;
  1186.             IF (build = kBuild) THEN
  1187.                 BEGIN
  1188.                 wDefProc := GetAndLoadWDefProc(windowDefProc);
  1189.                 saveState := GetHandleBits(wDefProc);
  1190.                 LockHandleHigh(wDefProc);
  1191.                 dontCare := CallWDefProc(GetWindowVariant(fWMgrWindow), fWMgrWindow, wCalcRgns, 0,
  1192.                                          wDefProc);
  1193.                 SetHandleBits(wDefProc, saveState);
  1194.  
  1195.                 { Calculate offset from top-left of window structure to top-left of window content}
  1196.                 topLeftInset := contRgn^^.rgnBBox.topleft;
  1197.                 SubPt(strucRgn^^.rgnBBox.topleft, topLeftInset);
  1198.                 fContRgnInset := topLeftInset;
  1199.                 globalStrucRect := WindowPeek(fWMgrWindow)^.strucRgn^^.rgnBBox;
  1200.                 globalContRect := WindowPeek(fWMgrWindow)^.contRgn^^.rgnBBox;
  1201.                 contDifference.v := (globalStrucRect.bottom - globalStrucRect.top) -
  1202.                                     (globalContRect.bottom - globalContRect.top);
  1203.                 contDifference.h := (globalStrucRect.right - globalStrucRect.left) -
  1204.                                     (globalContRect.right - globalContRect.left);
  1205.                 fContDifference := contDifference;
  1206.                 END;
  1207.             END;
  1208.         END;
  1209.     END;
  1210.  
  1211. {--------------------------------------------------------------------------------------------------}
  1212. {$S MAWindowRes}
  1213.  
  1214. FUNCTION TWindow.IsShown: BOOLEAN; OVERRIDE;
  1215.  
  1216.     BEGIN
  1217.     IF fWMgrWindow <> NIL THEN
  1218.         IsShown := Ord(WindowPeek(fWMgrWindow)^.visible) <> 0
  1219.     ELSE
  1220.         IsShown := FALSE;
  1221.     END;
  1222.  
  1223. {--------------------------------------------------------------------------------------------------}
  1224. {$S MAWindowRes}
  1225.  
  1226. PROCEDURE TWindow.Locate(h, v: VCoordinate;
  1227.                          invalidate: BOOLEAN); OVERRIDE;
  1228.     VAR
  1229.         currLoc: Point;
  1230.  
  1231.     BEGIN
  1232.  
  1233.     INHERITED Locate(h, v, invalidate);
  1234.  
  1235.     IF fWMgrWindow <> NIL THEN
  1236.         BEGIN
  1237.         currLoc := fWMgrWindow^.portRect.topleft;
  1238.         LocalToGlobal(currLoc);
  1239.         IF (h <> currLoc.h) | (v <> currLoc.v) THEN
  1240.             MoveWindow(fWMgrWindow, h, v, FALSE);        { ??? should offset by fContRgnInset.v }
  1241.         END;
  1242.     IF (fIsActive | fDoFirstClick) & IsShown THEN
  1243.         gApplication.InvalidateCursorRgn;                {??? should this be a view method? }
  1244.     END;
  1245.  
  1246. {--------------------------------------------------------------------------------------------------}
  1247. {$S MAWindowRes}
  1248.  
  1249. PROCEDURE TWindow.Select;
  1250.  
  1251.     BEGIN
  1252.     gApplication.SelectWMgrWindow(fWMgrWindow);
  1253.     END;
  1254.  
  1255. {--------------------------------------------------------------------------------------------------}
  1256. {$S MAWindowRes}
  1257.  
  1258. PROCEDURE TWindow.MoveByUser(globalMouse: Point);
  1259.  
  1260.     VAR
  1261.         boundsRect:         Rect;
  1262.         currLoc:            Point;
  1263.  
  1264.     BEGIN
  1265.     boundsRect := fMoveBounds;
  1266.     DragWindow(fWMgrWindow, globalMouse, boundsRect);
  1267.     gLastUpTime := TickCount;                            { needed for double clicking the title bar,
  1268.                                                          because DragWindow eats the mouseUpEvent }
  1269.  
  1270.     { Don't forget to tell the window object }
  1271.     currLoc := fWMgrWindow^.portRect.topLeft;
  1272.     LocalToGlobal(currLoc);
  1273.     Locate(currLoc.h, currLoc.v, kDontInvalidate);
  1274.     END;
  1275.  
  1276. {--------------------------------------------------------------------------------------------------}
  1277. {$S MAOpen}
  1278.  
  1279. PROCEDURE TWindow.Open; OVERRIDE;
  1280.  
  1281.     BEGIN
  1282.     IF NOT IsShown THEN
  1283.         BEGIN
  1284.         { Keep us matching the window since we are parallel structures }
  1285.         WITH fWMgrWindow^.portRect DO
  1286.             Resize(right - left, bottom - top, kDontInvalidate);    { Be sure all views are sized right }
  1287.  
  1288.         AdjustSize;                                     { Give non-template views a shot at
  1289.                                                          correcting for sizedeterminers }
  1290.  
  1291.         IF fMustAdapt & NOT fAdapted THEN
  1292.             AdaptToScreen;
  1293.         IF (fMustHorzCenter & NOT fHorzCentered) | (fMustVertCenter & NOT fVertCentered) THEN
  1294.             Center(fMustHorzCenter, fMustVertCenter, fIsModal);
  1295.         IF fMustStagger & NOT fStaggered THEN
  1296.             BEGIN
  1297.             { If both staggering and forcing on screen are specified then we must ensure
  1298.             that the window is forced on screen FIRST so that the staggering will occur
  1299.             in a visible (and usable) location.  BUT, after staggering we must STILL ensure
  1300.             that the window is forced on screen so, we reset the forced flag so that
  1301.             forcing will occur on schedule later. }
  1302.             IF fMustForceOnScreen & NOT fForcedOnScreen THEN
  1303.                 BEGIN
  1304.                 ForceOnScreen;
  1305.                 fForcedOnScreen := FALSE;                { Make sure we can be forced again }
  1306.                 END;
  1307.             SimpleStagger(kStdStaggerAmount, kStdStaggerAmount, gStdStaggerCount);
  1308.             END;
  1309.         IF fMustForceOnScreen & NOT fForcedOnScreen THEN
  1310.             ForceOnScreen;
  1311.  
  1312.         Show(TRUE, kRedraw);                            { Make me visible }
  1313.  
  1314.         END;
  1315.     INHERITED Open;                                     { Tell subviews to open in case they care }
  1316.     END;
  1317.  
  1318. {--------------------------------------------------------------------------------------------------}
  1319. {$S MANonRes}
  1320.  
  1321. PROCEDURE TWindow.Resize(width, height: VCoordinate;
  1322.                          invalidate: BOOLEAN); OVERRIDE;
  1323.  
  1324.     VAR
  1325.         r:                    Rect;
  1326.  
  1327.     BEGIN
  1328.     IF (width <> fSize.h) | (height <> fSize.v) THEN
  1329.         BEGIN
  1330.         SizeWindow(fWMgrWindow, width, height, invalidate);
  1331.         InvalidateFocus;
  1332.  
  1333.         IF fIsResizable & invalidate & Focus THEN
  1334.             BEGIN
  1335.  
  1336.             SetRect(r, - kSBarSizeMinus1, - kSBarSizeMinus1, 0, 0);
  1337.  
  1338.             OffsetRect(r, fSize.h, fSize.v);
  1339.             InvalidRect(r);
  1340.  
  1341.             OffsetRect(r, width - fSize.h, height - fSize.v);
  1342.             InvalidRect(r);
  1343.             END;
  1344.  
  1345.         INHERITED Resize(width, height, invalidate);
  1346.  
  1347.         IF (fIsActive | fDoFirstClick) & IsShown THEN
  1348.             gApplication.InvalidateCursorRgn;
  1349.         END;
  1350.     END;
  1351.  
  1352. {--------------------------------------------------------------------------------------------------}
  1353. {$S MANonRes}
  1354.  
  1355. PROCEDURE TWindow.ResizeByUser(globalMouse: Point);
  1356.  
  1357.     VAR
  1358.         growResult:         LONGINT;
  1359.         resizeLimits:        Rect;
  1360.  
  1361.     BEGIN
  1362.     IF fIsResizable THEN
  1363.         BEGIN
  1364.         resizeLimits := fResizeLimits;                    { GrowWindow may move SELF }
  1365.         growResult := GrowWindow(fWMgrWindow, globalMouse, resizeLimits);
  1366.         IF growResult <> 0 THEN
  1367.             Resize(LoWrd(growResult), HiWrd(growResult), kInvalidate);
  1368.         IF (fIsActive | fDoFirstClick) & IsShown THEN
  1369.             gApplication.InvalidateCursorRgn;
  1370.         END;
  1371.     END;
  1372.  
  1373. {--------------------------------------------------------------------------------------------------}
  1374. {$S MAOpen}
  1375.  
  1376. PROCEDURE TWindow.SetResizeLimits(itsMinSize, itsMaxSize: Point);
  1377.  
  1378.     TYPE
  1379.         WStateDataPtr        = ^WStateData;
  1380.         WStateDataHandle    = ^WStateDataPtr;
  1381.  
  1382.     BEGIN
  1383.     fResizeLimits.topleft := itsMinSize;
  1384.     fResizeLimits.botRight := itsMaxSize;
  1385.  
  1386.     { If the window is zoomable, keep the window's state data current }
  1387.     IF BAND(fProcID, zoomDocProc) <> 0 THEN
  1388.         WITH WStateDataHandle(WindowPeek(fWMgrWindow)^.DataHandle)^^.stdState DO
  1389.             BEGIN
  1390.             right := Min(right, fLocation.h + itsMaxSize.h - 1);
  1391.             bottom := Min(bottom, fLocation.v + itsMaxSize.v - 1);
  1392.             END;
  1393.     END;
  1394.  
  1395. {--------------------------------------------------------------------------------------------------}
  1396. {$S MAWindowRes}
  1397.  
  1398. PROCEDURE TWindow.SetTarget(newTarget: TEvtHandler);
  1399.  
  1400.     BEGIN
  1401.     IF newTarget = NIL THEN                             { Would be annoying if a nil got in here! }
  1402.         newTarget := SELF;
  1403.  
  1404.     fTarget := newTarget;
  1405.     IF gApplication.GetActiveWindow = SELF THEN
  1406.         gApplication.SetTarget(newTarget);
  1407.     END;
  1408.  
  1409. {--------------------------------------------------------------------------------------------------}
  1410. {$S MAWindowRes}
  1411.  
  1412. PROCEDURE TWindow.SetTitle(newTitle: Str255);
  1413.  
  1414.     VAR
  1415.         oldTitle:            Str255;
  1416.  
  1417.     BEGIN
  1418.     GetWTitle(fWMgrWindow, oldTitle);                    { to minimize flash, we only set the title
  1419.                                                          if it's different from the current title }
  1420.     IF CompareStrings(oldTitle, newTitle) <> sortsEqual THEN
  1421.         SetWTitle(fWMgrWindow, newTitle);
  1422.     END;
  1423.  
  1424. {--------------------------------------------------------------------------------------------------}
  1425. {$S MAFile}
  1426.  
  1427. PROCEDURE TWindow.SetTitleForDoc(newDocTitle: Str255);
  1428.  
  1429.     VAR
  1430.         title:                Str255;
  1431.  
  1432.     BEGIN
  1433.     IF fPreDocname > 0 THEN                             { optimize for case of nothing to do }
  1434.         BEGIN
  1435.         GetTitle(title);
  1436.  
  1437.         IF SubstituteInTitle(title, newDocTitle, fPreDocname, fConstTitle) THEN
  1438.             SetTitle(title);
  1439.         END;
  1440.     END;
  1441.  
  1442. {--------------------------------------------------------------------------------------------------}
  1443. {$S MANonRes}
  1444.  
  1445. PROCEDURE TWindow.Show(state, redraw: BOOLEAN); OVERRIDE;
  1446.  
  1447.     BEGIN
  1448.     IF (fWMgrWindow <> NIL) & redraw THEN
  1449.         IF (fIsActive | fDoFirstClick) THEN
  1450.             gApplication.InvalidateCursorRgn;
  1451.     IF state THEN
  1452.         BEGIN
  1453.         WITH fWMgrWindow^.portRect DO
  1454.             Resize(right - left, bottom - top, redraw);    { Be sure all views are sized right }
  1455.         ShowWindow(fWMgrWindow);
  1456.         END
  1457.     ELSE
  1458.         BEGIN
  1459.         HideWindow(fWMgrWindow);
  1460.         END;
  1461.  
  1462.     INHERITED Show(state, redraw);
  1463.     END;
  1464.  
  1465. {--------------------------------------------------------------------------------------------------}
  1466. {$S MAOpen}
  1467.  
  1468. PROCEDURE TWindow.SimpleStagger(dh, dv: integer;
  1469.                                 VAR counter: integer);
  1470.  
  1471.     VAR
  1472.         globalRect:         Rect;                        { The topLeft of the window must fall in
  1473.                                                          here. }
  1474.         Pt:                 Point;
  1475.         nSlots:             integer;
  1476.         slot:                integer;
  1477.  
  1478.     BEGIN
  1479.     fStaggered := TRUE;
  1480.     { Get window rect, which gives us globalRect.topLeft & size of window }
  1481.     GetGlobalBounds(globalRect);
  1482.  
  1483.     { Compute globalRect.botRight = globalRect.topleft + <bounds botRight> - <window botRight> }
  1484.     Pt := globalRect.topleft;
  1485.     AddPt(fMoveBounds.botRight, Pt);
  1486.     SubPt(globalRect.botRight, Pt);
  1487.     globalRect.botRight := Pt;
  1488.  
  1489.         { This covers the case of dh & dv both >= 0; if either is less than
  1490.         0, the right (bottom) limit is set to the left (top) edge of the
  1491.         screen -- allowing for some margin.  This makes the right (bottom)
  1492.         edge less than the left (top) edge, but this is OK since the DIV
  1493.         statement below will be dividing 2 negative numbers. }
  1494.  
  1495.     IF dh < 0 THEN
  1496.         globalRect.right := fMoveBounds.left;
  1497.     IF dv < 0 THEN
  1498.         globalRect.bottom := fMoveBounds.top;
  1499.  
  1500.     { This code avoids divide by zero problems }
  1501.     IF (dh = 0) | (dv = 0) THEN
  1502.         nSlots := 0
  1503.     ELSE
  1504.         nSlots := Min((globalRect.right - globalRect.left + dh - 1) DIV dh, (globalRect.bottom -
  1505.                       globalRect.top + dv - 1) DIV dv);
  1506.     IF nSlots = 0 THEN
  1507.         slot := 0
  1508.     ELSE
  1509.         slot := counter MOD nSlots;
  1510.  
  1511.     IF slot <> 0 THEN                                    { move the window }
  1512.         BEGIN
  1513.         { pt ends up as the place to position the window }
  1514.         Pt := globalRect.topleft;
  1515.  
  1516.         Pt.h := Pt.h + (slot * dh);
  1517.         Pt.v := Pt.v + (slot * dv);
  1518.  
  1519.         Locate(Pt.h, Pt.v, kDontInvalidate);
  1520.         END;
  1521.  
  1522.     counter := counter + 1;
  1523.     END;
  1524.  
  1525. {--------------------------------------------------------------------------------------------------}
  1526. {$S MAWindowRes}
  1527.  
  1528. PROCEDURE TWindow.Update; OVERRIDE;
  1529.  
  1530.     VAR
  1531.         fi:                 FailInfo;
  1532.  
  1533.     PROCEDURE HdlUpdate(error: OSErr;
  1534.                         message: LONGINT);
  1535.  
  1536.         BEGIN
  1537.         EndUpdate(fWMgrWindow);                         { Need to balance the BeginUpdate }
  1538.         { Or we get into an infinite loop }
  1539.         { trying to update the window when }
  1540.         { displaying an alert }
  1541.         InvalidateFocus;
  1542.         END;
  1543.  
  1544.     BEGIN
  1545.     IF HasPendingUpdate THEN
  1546.         BEGIN
  1547.         InvalidateFocus;
  1548.         BeginUpdate(fWMgrWindow);
  1549.  
  1550.         CatchFailures(fi, HdlUpdate);
  1551.         DrawContents;
  1552.         Success(fi);
  1553.  
  1554.         EndUpdate(fWMgrWindow);
  1555.         InvalidateFocus;
  1556.         END;
  1557.     END;
  1558.  
  1559. {--------------------------------------------------------------------------------------------------}
  1560. {$S MANonRes}
  1561.  
  1562. PROCEDURE TWindow.Zoom(partCode: integer);
  1563.  
  1564.     VAR
  1565.         aGDScreenRect:        Rect;
  1566.  
  1567.     PROCEDURE CalcZoomRect(forScreenRect: Rect);
  1568.  
  1569.         CONST
  1570.             edge                = 2;                    { leave space around window structure area,
  1571.                                                          ??? settable?}
  1572.  
  1573.         TYPE
  1574.             WStateDataPtr        = ^WStateData;
  1575.             WStateDataHandle    = ^WStateDataPtr;
  1576.  
  1577.         VAR
  1578.             zoomRect:            Rect;
  1579.             width, height:        integer;
  1580.  
  1581.         BEGIN
  1582.         InsetRect(forScreenRect, edge, edge);
  1583.         WITH forScreenRect DO
  1584.             BEGIN
  1585.             { calculate the maximum structure size }
  1586.             width := Min((right - left), fResizeLimits.botRight.h + fContDifference.h);
  1587.             height := Min((bottom - top), fResizeLimits.botRight.v + fContDifference.v);
  1588.  
  1589.             zoomRect.top := top + fContRgnInset.v + ((bottom - top) - height) DIV 2;
  1590.             zoomRect.left := left + fContRgnInset.h + ((right - left) - width) DIV 2;
  1591.             zoomRect.right := zoomRect.left + width - fContDifference.h - 1;
  1592.             zoomRect.bottom := zoomRect.top + height - fContDifference.v - 1;
  1593.  
  1594.             END;
  1595.  
  1596.         IF BAND(fProcID, zoomDocProc) <> 0 THEN
  1597.             WStateDataHandle(WindowPeek(fWMgrWindow)^.DataHandle)^^.stdState := zoomRect; { new
  1598.             zoom-out rect }
  1599.         END;
  1600.  
  1601.     BEGIN
  1602.     IF (qNeedsColorQD | gConfiguration.hasColorQD) & (partCode = inZoomOut) THEN { support multiple
  1603.            screens }
  1604.         BEGIN
  1605.         IF (GetMaxIntersectedDevice(aGDScreenRect) = NIL) THEN; { dont care about result }
  1606.         CalcZoomRect(aGDScreenRect);
  1607.         END;
  1608.  
  1609.     IF Focus THEN                                        { ??? (still true?) The ROM has a bug
  1610.                                                          requiring that thePort be the window being
  1611.                                                          zoomed. }
  1612.         BEGIN
  1613.         EraseRect(thePort^.portRect);                    { Erasing was suggested by Ernie B.; the
  1614.                                                          Finder does this. ??? is this _still_ a
  1615.                                                          good idea. Help stamp out flicker. }
  1616.         ZoomWindow(fWMgrWindow, partCode, FALSE);
  1617.  
  1618.         { let the View know what we've done }
  1619.         WITH fWMgrWindow^.portRect DO
  1620.             Resize(right - left, bottom - top, kInvalidate);
  1621.         END;
  1622.  
  1623.     IF (fIsActive | fDoFirstClick) & IsShown THEN
  1624.         gApplication.InvalidateCursorRgn;
  1625.     END;
  1626.  
  1627. {--------------------------------------------------------------------------------------------------}
  1628. {$S MANonRes}
  1629.  
  1630. PROCEDURE TWindow.ZoomByUser(globalMouse: Point;
  1631.                              partCode: integer);
  1632.  
  1633.     BEGIN
  1634.     IF TrackBox(fWMgrWindow, globalMouse, partCode) THEN
  1635.         Zoom(partCode);
  1636.     END;
  1637.  
  1638. {--------------------------------------------------------------------------------------------------}
  1639. {$S MAFields}
  1640.  
  1641. PROCEDURE TWindow.Fields(PROCEDURE DoToField(fieldName: Str255;
  1642.                                              fieldAddr: Ptr;
  1643.                                              fieldType: integer)); OVERRIDE;
  1644.  
  1645.     VAR
  1646.         theFlag:            BOOLEAN;
  1647.  
  1648.     BEGIN
  1649.     DoToField('TWindow', NIL, bClass);
  1650.     DoToField('fWMgrWindow', @fWMgrWindow, bWindowPtr);
  1651.     DoToField('fProcID', @fProcID, bInteger);
  1652.     DoToField('fMoveBounds', @fMoveBounds, bRect);
  1653.     DoToField('fResizeLimits', @fResizeLimits, bRect);
  1654.     DoToField('fTarget', @fTarget, bObject);
  1655.     DoToField('fTargetID', @fTargetID, bIDType);
  1656.     DoToField('fPreDocName', @fPreDocname, bInteger);
  1657.     DoToField('fConstTitle', @fConstTitle, bInteger);
  1658.     DoToField('fMustAdapt', @fMustAdapt, bBoolean);
  1659.     DoToField('fMustHorzCenter', @fMustHorzCenter, bBoolean);
  1660.     DoToField('fMustVertCenter', @fMustVertCenter, bBoolean);
  1661.     DoToField('fMustStagger', @fMustStagger, bBoolean);
  1662.     DoToField('fMustForceOnScreen', @fMustForceOnScreen, bBoolean);
  1663.     DoToField('fAdapted', @fAdapted, bBoolean);
  1664.     DoToField('fHorzCentered', @fHorzCentered, bBoolean);
  1665.     DoToField('fVertCentered', @fVertCentered, bBoolean);
  1666.     DoToField('fStaggered', @fStaggered, bBoolean);
  1667.     DoToField('fForcedOnScreen', @fForcedOnScreen, bBoolean);
  1668.     DoToField('fIsActive', @fIsActive, bBoolean);
  1669.     DoToField('fIsResizable', @fIsResizable, bBoolean);
  1670.     DoToField('fIsClosable', @fIsClosable, bBoolean);
  1671.     DoToField('fFreeOnClosing', @fFreeOnClosing, bBoolean);
  1672.     DoToField('fDisposeOnFree', @fDisposeOnFree, bBoolean);
  1673.     DoToField('fClosesDocument', @fClosesDocument, bBoolean);
  1674.     DoToField('fOpenInitially', @fOpenInitially, bBoolean);
  1675.     DoToField('fIsModal', @fIsModal, bBoolean);
  1676.     DoToField('fDoFirstClick', @fDoFirstClick, bBoolean);
  1677.     DoToField('fFloats', @fFloats, bBoolean);
  1678.     DoToField('fContRgnInset', @fContRgnInset, bPoint);
  1679.     DoToField('fContDifference', @fContDifference, bPoint);
  1680.     INHERITED Fields(DoToField);
  1681.     END;
  1682.